#pragma once

#include <AVUIIClientRendererInterface.h>
#include <AVUIEventableObject.h>

struct IDirect3DTexture9;
class UIRenderer;
class TextureManager;
 
class LoadableObject : public AVUI::DispatcherObject
{
public:
    LoadableObject(AVUI::Uri* pSource, const WCHAR* wzBasePath) : m_pUri(pSource), m_wzBasePath(wzBasePath) { }

    AVUI::Uri* get_Source() { return m_pUri; }
    const WCHAR* get_BasePath() { return m_wzBasePath; }
    void LoadData();

protected:
    virtual void FinalizeLoad(AVUI::TArrayPtr<char> pData) = 0;

private:

    AVUI::TRefCountedPtr<AVUI::Uri> m_pUri;
    const WCHAR* m_wzBasePath;
};

class BitmapSourceData : public LoadableObject, public AVUI::IClientImageSource
{
    friend class TextureManager;
public:
    BitmapSourceData(TextureManager* pTextureManager, AVUI::Uri* pUri, const WCHAR* wzBasePath);

    float get_Height() { return m_height; }
    float get_Width() { return m_width; }
    void Destroy();

    IDirect3DTexture9* get_Texture() { return m_pTexture; }

    void add_DownloadCompleted(AVUI::EventHandler* pValue) { AddEventHandler(get_DownloadCompletedEvent(), (AVUI::Delegate*)pValue); }
    void remove_DownloadCompleted(AVUI::EventHandler* pValue) { RemoveEventHandler(get_DownloadCompletedEvent(), (AVUI::Delegate*)pValue); }
    DECLARE_EVENT(DownloadCompleted);

    void add_DownloadProgress(AVUI::EventHandler* pValue) { AddEventHandler(get_DownloadProgressEvent(), (AVUI::Delegate*)pValue); }
    void remove_DownloadProgress(AVUI::EventHandler* pValue) { RemoveEventHandler(get_DownloadProgressEvent(), (AVUI::Delegate*)pValue); }
    DECLARE_EVENT(DownloadProgress);

    void add_DownloadFailed(AVUI::EventHandler* pValue) { AddEventHandler(get_DownloadFailedEvent(), (AVUI::Delegate*)pValue); }
    void remove_DownloadFailed(AVUI::EventHandler* pValue) { RemoveEventHandler(get_DownloadFailedEvent(), (AVUI::Delegate*)pValue); }
    DECLARE_EVENT(DownloadFailed);

protected:

    virtual void FinalizeLoad(AVUI::TArrayPtr<char> pData);

private:

    void FinalizeLoadMainThread(Object* pSender, Object* pArgs);
    void LoadImageData();

    void DeviceLost();
    void DeviceReset();

    TextureManager* m_pTextureManager;

    IDirect3DTexture9* m_pTexture;
    float m_width;
    float m_height;
};

class TextureManager
{
    friend class BitmapSourceData;
public:
    TextureManager(UIRenderer* pRenderer);
    ~TextureManager();

    AVUI::IClientImageSource* LoadImageSource(AVUI::Uri* pImageUri);

    void DeviceLost();
    void DeviceReset();

    IDirect3DDevice9* get_Device();
    const WCHAR* get_BasePath();

private:

    void RemoveSourceData(BitmapSourceData* pData);

    AVUI::ItemStructList< AVUI::TRefCountedPtr<BitmapSourceData> > m_imageSourceData;
    UIRenderer* m_pRenderer;
};

class LoadManager
{
public:
    static void LoadObject(LoadableObject* pToLoad);

    static void LoadThreadProc();
private:
    static bool m_isInitialized;
    static AVUI::ItemStructList< AVUI::TRefCountedPtr<LoadableObject> > m_objectsToLoad;
    static HANDLE m_hHasData;
};

